home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / PROGNG_C / TURBOCU1.LZH / XC3.ARC / XC3.C next >
Text File  |  1987-07-14  |  44KB  |  1,520 lines

  1. /********************************************************************/
  2. /*                                                                  */
  3. /*  XC  -  A 'C' Xref Utility                                       */
  4. /*                                                                  */
  5. /*  Version 1.0   January, 1982                                     */
  6. /*                                                                  */
  7. /*  Copyright (c) 1982 by Philip N. Hisley                          */
  8. /*                                                                  */
  9. /*    Philip N. Hisley                                              */
  10. /*    548H Jamestown Court                                          */
  11. /*    Edgewood, Maryland 21040                                      */
  12. /*    (301) 679-4606                                                */
  13. /*                                                                  */
  14. /*  Released for non-commercial distribution only                   */
  15. /*                                                                  */
  16. /*  Converted to IBM/PC CI/C86 by David N. Smith, May/June 1983     */
  17. /*  with enhancements and Lattice compiler support in December 1983.*/
  18. /*                                                                  */
  19. /*    David N. Smith                                                */
  20. /*    44 Ole Musket Lane                                            */
  21. /*    Danbury, CT 06810                                             */
  22. /*    (203) 748-5934                                                */
  23. /*    CompuServe: 73145,153                                         */
  24. /*                                                                  */
  25. /*  Changes Copyright (c) 1983 by David N. Smith                    */
  26. /*  Permission granted to copy for non-commercial purporses.        */
  27. /*                                                                  */
  28. /*  PC Enhancements include:                                        */
  29. /*                                                                  */
  30. /*    1)  Nested #INCLUDE statements                                */
  31. /*    2)  Single spaced cross-reference list                        */
  32. /*    3)  Removal of tabbing on output device                       */
  33. /*        (Since many printers don't support it)                    */
  34. /*    4)  #INCLUDE statements with both "--" and <-->               */
  35. /*        syntax and with a full fileid in the quotes.              */
  36. /*    5)  Multiple input filenames on command line.                 */
  37. /*                                                                  */
  38. /*                                                                  */
  39. /*  Minor additions by John Beamish, June 1984                      */
  40. /*                                                                  */
  41. /*    John Beamish                                                  */
  42. /*    Box 340, Station T                                            */
  43. /*    Toronto, Ontario                                              */
  44. /*    M6B 4A3                                                       */
  45. /*    (416) 782-1770                                                */
  46. /*                                                                  */
  47. /*  Changes Copyright (c) 1984 by John Beamish.                     */
  48. /*  Permission granted to copy for non-commercial purposes.         */
  49. /*                                                                  */
  50. /*  1.  Added reserved words ENUM and VOID.                         */
  51. /*  2.  Variable names extended to 31 characters.                   */
  52. /*  3.  Tab option on command line.  Tabs are expanded to number    */
  53. /*      of spaces specified in value with -t flag.  Default is 4.   */
  54. /*  4.  Cross-reference prints a blank line when the first          */
  55. /*      character changes.                                          */
  56. /*  5.  Command line errors reported in a more descriptive fashion. */
  57. /*  6.  Listing "tidied-up" and some comments added.                */
  58. /*                                                                  */
  59. /*  Converted to TURBOC (COMPACT MODEL) by                          */
  60. /*                                                                  */
  61. /*      Dean Limbaugh                                               */
  62. /*      6329 NW 28 Terrace                                          */
  63. /*      Gainesville, Fl, 32606                                      */
  64. /*      CIS 72765,1162                                              */
  65. /*                                                                  */
  66. /*  Changes Copyright (c) 1987 by Dean Limbaugh                     */
  67. /*  Permission granted to copy for non-commercial purposes.         */
  68. /*                                                                  */
  69. /*  1.  Added reserved words ASM, CDECL, CONST, FAR, INTERRUPT,     */
  70. /*                           NEAR, PASCAL, VOLATILE.                */
  71. /*  2.  Added s & l options to -i.                                  */
  72. /*  3.  Added -f, -p, -s, -q options.                               */
  73. /*  4.  Changed input to fix look ahead problem. (If identifier     */
  74. /*      was last token on line, XREF would show it on the next line)*/
  75. /*  5.  Changed output to fix look ahead problem. (would print an   */
  76. /*      extra blank line at EOF)                                    */
  77. /*  6.  Changed include file processing to scan whole card.         */
  78. /*  7.  Changed how hash table is handled to remove restriction on  */
  79. /*      number of identifiers allowed. Now limited only by available*/
  80. /*      memory.                                                     */
  81. /*  8.  Changed title line to center file name and adjust to line   */
  82. /*      width and changed XREF output to print the maximum number   */
  83. /*      of references that would fit on a line.                     */
  84. /*  9.  Many other small changes.                                   */
  85. /*                                                                  */
  86. /*  Lookahead problem still exists in printing reference table.     */
  87. /*  That is, the program does not look to see if there are any      */
  88. /*  references left to print when the current line becomes full     */
  89. /*  so that if there are exactly as many references for an          */
  90. /*  identifier as will fit on a line, an extra blank line will be   */
  91. /*  printed.                                                        */
  92. /*                                                                  */
  93. /*  A good way to see how this program works is to use it on itself.*/
  94. /*  For example:                                                    */
  95. /*                                                                  */
  96. /*    xc xc.c -i > prn                                              */
  97. /*                                                                  */
  98. /*  will run the program on itself, include the #include files      */
  99. /*  and direct the output to the printer.                           */
  100. /*                                                                  */
  101. /*  Uploaded to PCanada by John Beamish (PC1048).                   */
  102. /*                                                                  */
  103. /*                                                                  */
  104. /*  Abstract:                                                       */
  105. /*                                                                  */
  106. /*    'XC' is a cross-reference utility for 'C' programs.           */
  107. /*    It has the ability to handle nested include files             */
  108. /*    to a depth of 8 levels and properly processes nested          */
  109. /*    comments as supported by BDS C. Option flags support          */
  110. /*    the following features:                                       */
  111. /*                                                                  */
  112. /*    - Routing of list output to disk                              */
  113. /*    - Cross-referencing of reserved words                         */
  114. /*    - Processing of nested include files                          */
  115. /*    - Generation of listing only                                  */
  116. /*                                                                  */
  117. /*    Usage: xc <filename> <flag(s)>                                */
  118. /*                                                                  */
  119. /*    Flags:                                                        */
  120. /*    -i <s|l>       = Enable file inclusion                        */
  121. /*                     s = system include files                     */
  122. /*                     l = local  include files                     */
  123. /*    -l             = Generate listing only                        */
  124. /*    -r             = Cross-ref reserved words                     */
  125. /*    -o <filename>  = Write output to named file                   */
  126. /*    -w <width>     = No of output columns                         */
  127. /*    -t <number>    = Number of spaces to expand each tab          */
  128. /*    -f <filename>  = File containing a list of file names         */
  129. /*    -p <pathname>  = Search path for include files                */
  130. /*    -s             = Print hashing stats                          */
  131. /*    -q             = Don't print dots                             */
  132. /*                                                                  */
  133. /*    Note that flags -o -w -t -f -p must be immediately followed   */
  134. /*    by the value for the flag.                                    */
  135. /*                                                                  */
  136. /********************************************************************/
  137.  
  138. #include <stdio.h>
  139. #include <ctype.h>
  140. #include <string.h>
  141. #include <process.h>
  142. #include <stdlib.h>
  143.  
  144. #if  !defined(TRUE)
  145. #define    TRUE     1
  146. #define    FALSE    0
  147. #endif
  148.  
  149. #define    LINES_PER_PAGE   60  /* printed lines per page           */
  150. #define    MAX_COL          78  /* def max col nmbr for list line   */
  151. #define    MIN_COL          30  /* minimum value for -w option      */
  152. #define    MIN_TAB           2  /* minimum value for -t option      */
  153. #define    MAX_TAB          10  /* maximum value for -t option      */
  154. #define    MAX_REF           5  /* maximum refs per ref-block       */
  155. #define    MAX_LEN          65  /* maximum identifier length        */
  156. #define    MAX_WRD         749  /* maximum number of identifiers    */
  157. #define    MAX_ALPHA        53  /* maximum alpha chain heads        */
  158. #define    ERROR            -1  /* error flag                       */
  159. #define    FF             0x0C  /* formfeed                         */
  160. #define    TAB               4  /* default value for -t option      */
  161. #define    START_COLUMN     11  /* column of list line for source   */
  162.  
  163. typedef struct  RfBlk
  164.   {
  165. int     RefItem[MAX_REF];
  166. int     RefCnt;
  167. struct  RfBlk *Next;
  168.   } RfBlk;
  169.  
  170. typedef struct  IdBlk
  171.   {
  172. char         *IdName;
  173. struct IdBlk *IdNext;
  174. struct IdBlk *AlphaLnk;
  175. struct RfBlk *TopLnk;
  176. struct RfBlk *LstLnk;
  177.   } IdBlk;
  178.  
  179. typedef struct HashBlk
  180.   {
  181. struct IdBlk *IdFirst;
  182. int           IdCount;
  183.   } HashBlk;
  184.  
  185. typedef struct  AlphaHdr
  186.   {
  187. struct IdBlk *AlphaTop;
  188. struct IdBlk *AlphaLst;
  189.   } AlphaHdr;
  190.  
  191. /********************************************************************/
  192. /*                                                                  */
  193. /* function prototypes                                              */
  194. /*                                                                  */
  195. /********************************************************************/
  196.  
  197. void          main(int PArgC,char **PArgV);
  198. void          ListErr(void);
  199. void          UseErr(int X);
  200. int           ProcFile(char *FileName,int IncNum);
  201. void          GetIncludeFileId(char *Token,FILE *InFile,int *SysSw);
  202. void          Echo(char Ch);
  203. void          InitOutput(void);
  204. void          EchoLine(void);
  205. void          CheckPage(void);
  206. int           GetToken(FILE *InFile ,char *Token,int  *TokLen,
  207.                        int  *EofFlag);
  208. int           FileChar(FILE *InFile,int *Eof);
  209. int           RdChar(FILE *InFile,int *EofFlag,int EchoFlag);
  210. int           CheckToken(char *Token);
  211. void          PutToken(char *Token,int Ref);
  212. void          ChainAlpha(struct IdBlk *CaPtr,char *CaToken);
  213. struct IdBlk *AllocId(char *Token);
  214. struct RfBlk *AllocRf(int Ref);
  215. struct RfBlk *AddRf(struct RfBlk *Ptr,int Ref);
  216. void         PrintTable(void);
  217. void         PrintHeader(void);
  218. void         NL(void);
  219.  
  220. /********************************************************************/
  221.  
  222. AlphaHdr  AlphaVector[MAX_ALPHA];
  223. HashBlk   IdVector[MAX_WRD];
  224.  
  225. int   PageNo;            /* page number                             */
  226. int   PageLine;          /* page line counter                       */
  227. int   LineNum;           /* line number                             */
  228. int   EditNum;           /* edit line number                        */
  229. int   IdCnt;             /* number of unique identifiers            */
  230. int   FileLevel;         /* file level                              */
  231. int   Dummy;             /* dummy integer                           */
  232. int   MaxCol = MAX_COL;  /* maximum right column for listing line   */
  233. int   Tab    = TAB;      /* standard tab expansion                  */
  234. int   PrtRef;            /* on when printing XREF                   */
  235. int   CurChar;           /* Current character pos in output buff    */
  236. int   MaxChar;           /* Maximum # chars is output buff          */
  237.  
  238. char *LinePtr;           /* Pointer to line buffer                  */
  239.  
  240. char  ActFile[MAX_LEN];
  241. char  LstFile[MAX_LEN];
  242. char  GblFile[MAX_LEN];
  243. char  NameFile[MAX_LEN];
  244. char  PathName[MAX_LEN];
  245.  
  246. FILE *FLstFile;
  247.  
  248. int   IsFlag;                   /* System file inclusion flag       */
  249. int   IlFlag;                   /* Local  file inclusion flag       */
  250. int   LFlag;                    /* Listing only flag                */
  251. int   OFlag;                    /* Output file flag                 */
  252. int   RFlag;                    /* XREF reserved words              */
  253. int   FFlag;                    /* File list file flag              */
  254. int   QFlag;                    /* Quiet mode flag                  */
  255. int   SFlag;                    /* Print hashing stats flag         */
  256. int   CFlag;                    /* Current out buffer is a cont.    */
  257.  
  258. /********************************************************************/
  259.  
  260. void main(int PArgC,char **PArgV)
  261.   {
  262. char  *Arg;
  263. int    ArgC;
  264. char **ArgV;
  265. int    I;
  266. FILE  *NameIn;
  267.  
  268.   ArgC = PArgC;
  269.   ArgV = PArgV;
  270.  
  271.   if (ArgC < 2)
  272.     UseErr('f');
  273.  
  274.   IsFlag      = FALSE;
  275.   IlFlag      = FALSE;
  276.   LFlag       = FALSE;
  277.   OFlag       = FALSE;
  278.   RFlag       = FALSE;
  279.   FFlag       = FALSE;
  280.   SFlag       = FALSE;
  281.   QFlag       = TRUE;
  282.  
  283.   PathName[0] = '\0';
  284.  
  285.   while (--ArgC != 0)
  286.     {
  287.     if (*(Arg = *++ArgV) == '-')
  288.       {
  289.       switch(tolower(*++Arg))
  290.         {
  291.       case 'i':
  292.         if (*++Arg == '\0')
  293.           {
  294.           IsFlag = !IsFlag;
  295.           IlFlag = !IlFlag;
  296.           }
  297.         else
  298.           do
  299.             {
  300.             switch(tolower(*Arg))
  301.               {
  302.             case 's':
  303.               IsFlag = !IsFlag;
  304.               break;
  305.  
  306.             case 'l':
  307.               IlFlag = !IlFlag;
  308.               break;
  309.  
  310.             case '\0':
  311.               break;
  312.  
  313.             default:
  314.               UseErr('i');
  315.               }
  316.             } while (*++Arg != '\0');
  317.  
  318.         break;
  319.  
  320.       case 'l':
  321.         LFlag = !LFlag;
  322.         break;
  323.  
  324.       case 'o':
  325.         OFlag = !OFlag;
  326.  
  327.         strcpy(LstFile,++Arg);
  328.  
  329.         if (LstFile[0] == '-')
  330.           UseErr('o');
  331.  
  332.         break;
  333.  
  334.       case 'r':
  335.         RFlag = !RFlag;;
  336.         break;
  337.  
  338.       case 't':
  339.         I = atoi(++Arg);
  340.  
  341.         if (I < MIN_TAB || I > MAX_TAB)
  342.           UseErr('t');
  343.  
  344.         Tab = I;
  345.         break;
  346.  
  347.       case 'w':
  348.         I = atoi(++Arg);
  349.  
  350.         if (I <= MIN_COL || I >= 255)
  351.           UseErr('w');
  352.  
  353.         MaxCol = I;
  354.         break;
  355.  
  356.       case 'f':
  357.         FFlag = !FFlag;;
  358.         strcpy(NameFile,++Arg);
  359.         break;
  360.  
  361.       case 'p':
  362.         strcpy(PathName,++Arg);
  363.         break;
  364.  
  365.       case 's':
  366.         SFlag = !SFlag;
  367.         break;
  368.  
  369.       case 'q':
  370.         QFlag = !QFlag;
  371.         break;
  372.  
  373.       default:
  374.         UseErr('x');
  375.         }
  376.       }
  377.     }
  378.  
  379.   if (OFlag)
  380.     {
  381.     if ((FLstFile = fopen(LstFile,"w")) == NULL)
  382.       {
  383.       printf("ERROR: Unable to create list file - %s\n",LstFile);
  384.       exit(1);
  385.       }
  386.     printf("XC: C XREF Utility  v2.0\n\n");
  387.     }
  388.  
  389.   for (LineNum = 0;LineNum < MAX_ALPHA;LineNum++)
  390.     {
  391.     AlphaVector[LineNum].AlphaTop = NULL;
  392.     AlphaVector[LineNum].AlphaLst = NULL;
  393.     }
  394.  
  395.   for (LineNum = 0;LineNum < MAX_WRD;LineNum++)
  396.     {
  397.     IdVector[LineNum].IdFirst = NULL;
  398.     IdVector[LineNum].IdCount = 0;
  399.     }
  400.  
  401.   InitOutput();
  402.  
  403.   PrtRef    = FALSE;
  404.   LineNum   = 1;
  405.   FileLevel = 0;
  406.   PageLine  = 0;
  407.   PageNo    = 0;
  408.   EditNum   = 1;
  409.   IdCnt     = 0;
  410.  
  411.   if (PathName[0] == '\0')
  412.     strcpy(PathName,"\\TURBOC\\INCLUDE\\");
  413.  
  414.   ArgC      = PArgC;
  415.   ArgC--;
  416.   ArgV      = PArgV;
  417.  
  418.   while (ArgC--)
  419.     {
  420.     strcpy(GblFile,*++ArgV);
  421.  
  422.     if (*GblFile == '-')
  423.       continue;
  424.  
  425.     ProcFile(GblFile,Dummy);
  426.     }
  427.  
  428.   if (FFlag)
  429.     {
  430.     if ((NameIn = fopen(NameFile,"r")) == NULL)
  431.       {
  432.       printf("ERROR: Unable to open Names file - %s\n",NameFile);
  433.       exit(1);
  434.       }
  435.  
  436.     while (fgets(GblFile,MAX_LEN,NameIn) != NULL)
  437.       {
  438.       GblFile[strlen(GblFile)- 1] = '\0'; /* remove trailing LF      */
  439.       ProcFile(GblFile,Dummy);
  440.       }
  441.  
  442.     fclose(NameIn);
  443.     }
  444.  
  445.   if (!LFlag)
  446.     {
  447.     GblFile[0] = '\0';
  448.     PrintTable();
  449.     printf("\nUnique    Symbols: %d\n",IdCnt);
  450.     }
  451.  
  452.   if (OFlag)
  453.     {
  454.     NL();
  455.     fclose(FLstFile);
  456.     }
  457.   }
  458.  
  459. /********************************************************************/
  460.  
  461. void InitOutput(void)
  462.   {
  463.   MaxChar = MaxCol - START_COLUMN;
  464.  
  465.   if ((LinePtr = calloc(1,MaxChar + 1)) == NULL)
  466.     {
  467.     printf("ERROR: Unable to allocate line buffer\n");
  468.     exit(1);
  469.     }
  470.  
  471.   CurChar = 0;
  472.   CFlag   = FALSE;
  473.   }
  474.  
  475. /********************************************************************/
  476.  
  477. void ListErr(void)
  478.   {
  479.   printf("\nERROR: Write error on list output file - %s\n", LstFile);
  480.   exit(1);
  481.   }
  482.  
  483. /********************************************************************/
  484.  
  485. void UseErr(int X)
  486.   {
  487.   printf("\nERROR: Invalid parameter specification.  ");
  488.  
  489.   if (X == 'f')
  490.     {
  491.     printf("No/invalid input file name specified.");
  492.     }
  493.   else
  494.     {
  495.     if (X == 'x')
  496.       {
  497.       printf("Switch not recognized.");
  498.       }
  499.     else
  500.       {
  501.       printf("Error in switch %c.",X);
  502.       }
  503.     }
  504.  
  505.   printf("\n\nUsage: xc filename1 <filename2>... <flag(s)>\n\n");
  506.   printf("Flags: -i <s|l>        = Enable file inclusion\n");
  507.   printf("                         s = include system files\n");
  508.   printf("                         l = include local  files\n");
  509.   printf("       -l              = Generate listing only\n");
  510.   printf("       -r              = Cross-reference reserved words\n");
  511.   printf("       -o <outfile>    = Write output to named file\n");
  512.   printf("       -t <tab width>  = Number of spaces to expand tabs\n");
  513.   printf("       -w <width>      = Width of output page\n");
  514.   printf("       -f <filename>   = Name of file containing list\n");
  515.   printf("       -p <pathname>   = Path to use for include files\n");
  516.   printf("       -s              = Print hashing stats\n");
  517.   printf("       -q              = Quiet mode\n\n");
  518.   printf("Flags -o, -t, -w, -f, and -p must be followed immediately by\n");
  519.   printf("value of the flag.\n\n");
  520.   printf("E.G. -w132\n\n");
  521.   exit(1);
  522.   }
  523.  
  524. /********************************************************************/
  525.  
  526. int ProcFile(char *FileName,int IncNum)
  527.  
  528.   /* IncNum : prev. included line nmbr (return to caller)  */
  529.  
  530.   {
  531. char     Token[MAX_LEN];        /* token buffer                     */
  532. int      EofFlag;               /* end-of-file indicator            */
  533. int      TokLen;                /* token length                     */
  534. FILE    *InFile;                /* input file                       */
  535. int      SysSw;                 /* System include file indicator    */
  536.  
  537.   strcpy(ActFile,FileName);
  538.  
  539.   EditNum = 1;
  540.  
  541.   if ((InFile = fopen(FileName,"r")) == NULL)
  542.     {
  543.     printf("\nERROR: Unable to open input file: %s\n",FileName);
  544.     return(IncNum);
  545.     }
  546.  
  547.   if (FileLevel++ == 0)
  548.     PrintHeader();
  549.  
  550.   EofFlag = FALSE;
  551.  
  552.   do
  553.     {
  554.     if (GetToken(InFile,Token,&TokLen,&EofFlag))
  555.       if (CheckToken(Token))
  556.         {
  557.         if (strcmp(Token,"#include") == 0)
  558.           {
  559.           GetIncludeFileId(Token,InFile,&SysSw);
  560.  
  561.           if ((IsFlag && SysSw) || (IlFlag && !SysSw))
  562.             {
  563.             EditNum = ProcFile(Token,EditNum);
  564.             strcpy(ActFile,FileName);
  565.             }
  566.  
  567.           continue;
  568.           }
  569.  
  570.         PutToken(Token,LineNum);
  571.         }
  572.     } while (!EofFlag);
  573.  
  574.   FileLevel -= 1;
  575.   fclose(InFile);
  576.  
  577.   return(IncNum);
  578.   }
  579.  
  580. /********************************************************************/
  581.  
  582. void GetIncludeFileId(char *Token,FILE *InFile,int *SysSw)
  583.   {
  584. char    Ch;
  585. char    Term;
  586.  
  587.   while ((((Term = getc(InFile)) == ' ') ||
  588.            (Term == '\t')                ||
  589.            (Term == '\n'))               &&
  590.            (Term != ERROR))
  591.     Echo(Term);
  592.  
  593.   if (Term == ERROR)
  594.     {
  595.     printf("Error scanning #INCLUDE fileid(1): %c\n",Term);
  596.     exit(1);
  597.     }
  598.  
  599.   Echo(Term);
  600.  
  601.   *SysSw = (Term == '<');
  602.  
  603.   if (*SysSw)
  604.     Term = '>';                 /* terminator is > or "             */
  605.  
  606.   if ((!*SysSw) && (Term != '"'))
  607.     {
  608.     printf("Error scanning #INCLUDE fileid(2): %c\n",Term);
  609.     exit(1);
  610.     }
  611.  
  612.   if (*SysSw)
  613.     {
  614.     strcpy(Token,PathName);
  615.     Token += strlen(PathName);
  616.     }
  617.  
  618.   do
  619.     {
  620.     if ((Ch = getc(InFile)) != ' ')
  621.       {
  622.       *Token++ = Ch;
  623.       }
  624.  
  625.     Echo(Ch);
  626.     } while ((Ch != Term) && Ch != ERROR);
  627.  
  628.   if (Ch == ERROR)
  629.     {
  630.     printf("Error scanning #INCLUDE fileid(3): %c\n",Term);
  631.     exit(1);
  632.     }
  633.  
  634.   *--Token = '\0';
  635.  
  636.   while (((Term = getc(InFile)) != '\n') &&
  637.           (Term != ERROR))
  638.     Echo(Term);
  639.  
  640.   Echo('\n');
  641.   }
  642.  
  643. /********************************************************************/
  644.  
  645. void Echo(char Ch)
  646.   {
  647.   if (Ch == '\t')
  648.     {
  649.     do
  650.       {
  651.       LinePtr[CurChar++] = ' ';
  652.       } while ((CurChar <= MaxChar) && ((CurChar % Tab) != 0));
  653.  
  654.     CurChar--;
  655.     }
  656.   else if (Ch == '\n')
  657.     EchoLine();
  658.   else
  659.     LinePtr[CurChar++] = Ch;
  660.  
  661.   if (CurChar == MaxChar)
  662.     {
  663.     EchoLine();
  664.     CFlag = TRUE;
  665.     }
  666.   }
  667.  
  668. /********************************************************************/
  669.  
  670. void EchoLine(void)
  671.   {
  672.   LinePtr[CurChar] = '\0';
  673.   CurChar          = 0;
  674.  
  675.   CheckPage();
  676.  
  677.   if (CFlag)
  678.     {
  679.     CFlag = FALSE;
  680.  
  681.     if (OFlag)
  682.       {
  683.       if (fprintf(FLstFile,"           %s\n",LinePtr) == ERROR)
  684.         ListErr();
  685.       }
  686.     else
  687.       printf("           %s\n",LinePtr) ;
  688.     }
  689.   else if (OFlag)
  690.     {
  691.     if (fprintf(FLstFile,"%4d %4d: %s\n",
  692.                 LineNum++,EditNum++,LinePtr) == ERROR)
  693.         ListErr();
  694.     }
  695.   else
  696.     printf("%4d %4d: %s\n",LineNum++,EditNum++,LinePtr) ;
  697.   }
  698.  
  699. /********************************************************************/
  700.  
  701. void CheckPage(void)
  702.   {
  703.   if (++PageLine > LINES_PER_PAGE)
  704.     PrintHeader();
  705.  
  706.   if (!PrtRef && OFlag && !QFlag)
  707.     if (LineNum % 60 == 1)
  708.       printf("\n<%4d> ",LineNum);
  709.     else
  710.       printf(".");
  711.   }
  712.  
  713. /********************************************************************/
  714. /*                                                                  */
  715. /*  'getoken' returns the next valid identifier or                  */
  716. /*  reserved word from a given file along with the                  */
  717. /*  character length of the token and an end-of-file                */
  718. /*  indicator                                                       */
  719. /*                                                                  */
  720. /********************************************************************/
  721.  
  722. int GetToken(FILE *InFile,
  723.              char *Token,
  724.              int  *TokLen,
  725.              int  *EofFlag)
  726.   {
  727. int    C;
  728. char  *HToken;
  729. char   TempChar;
  730.  
  731.   HToken = Token;
  732.  
  733.   gtk:
  734.     *TokLen = 0;
  735.     Token   = HToken;
  736.  
  737. /*                                                                  */
  738. /*  Scan and discard any characters until an alphabetic or          */
  739. /*  '_' (underscore) character is encountered or an end-of-file     */
  740. /*  condition occurs                                                */
  741. /*                                                                  */
  742.  
  743.   while ((!isalpha(*Token = RdChar(InFile,EofFlag,FALSE))) &&
  744.           !*EofFlag                                        &&
  745.            *Token != '_'                                   &&
  746.            *Token != '0'                                   &&
  747.            *Token != '#')
  748.     ;
  749.  
  750.   if (*EofFlag)
  751.     return(FALSE);
  752.  
  753.   (*TokLen)++;
  754.  
  755. /*                                                                  */
  756. /*  Scan and collect identified alpanumeric token until             */
  757. /*  a non-alphanumeric character is encountered or and              */
  758. /*  end-of-file condition occurs                                    */
  759. /*                                                                  */
  760.  
  761.   TempChar = '_';
  762.  
  763.   while ((isalpha(C = RdChar(InFile,EofFlag,TRUE)) ||
  764.           isdigit(C)                               ||
  765.           C == '_'                                 ||
  766.           C == TempChar)                           &&
  767.         !*EofFlag)
  768.     {
  769.     Echo(C);
  770.  
  771.     if (*TokLen < MAX_LEN)
  772.       {
  773.       *++Token = C;
  774.       (*TokLen)++;
  775.       }
  776.     }
  777.  
  778.   ungetc(C,InFile);
  779.  
  780. /*                                                                  */
  781. /*  Check to see if a numeric hex or octal constant has             */
  782. /*  been encountered ... if so dump it and try again                */
  783. /*                                                                  */
  784.  
  785.   if (*HToken == '0')
  786.     goto gtk;
  787.  
  788. /*                                                                  */
  789. /*  Tack a NULL character onto the end of the token                 */
  790. /*                                                                  */
  791.  
  792.   *++Token = '\0';
  793.  
  794. /*                                                                  */
  795. /*  Screen out all #token strings except #include                   */
  796. /*                                                                  */
  797.  
  798.   if (*HToken == '#' && strcmp(HToken,"#include"))
  799.     goto gtk;
  800.  
  801.   return(TRUE);
  802.   }
  803.  
  804. /********************************************************************/
  805.  
  806. int FileChar(FILE *InFile,int *Eof)
  807.   {
  808. int Char;
  809.  
  810.   Char = getc(InFile);
  811.  
  812.   if (Char == ERROR)
  813.     {
  814.     if (ferror(InFile))
  815.       {
  816.       printf("\nERROR: Error while processing input file - %s\n",ActFile);
  817.       exit(1);
  818.       }
  819.     else
  820.       {
  821.       *Eof = TRUE;
  822.       Char = 0;
  823.       }
  824.     }
  825.  
  826.   return(Char);
  827.   }
  828.  
  829. /********************************************************************/
  830. /*                                                                  */
  831. /*  'RdChar' returns the next valid character in a file             */
  832. /*  and an end-of-file indicator. A valid character is              */
  833. /*  defined as any which does not appear in either a                */
  834. /*  commented or a quoted string ... 'RdChar' will correctly        */
  835. /*  handle comment tokens which appear within a quoted              */
  836. /*  string                                                          */
  837. /*                                                                  */
  838. /********************************************************************/
  839.  
  840. int RdChar(FILE *InFile,int *EofFlag,int EchoFlag)
  841.   {
  842. int    C;
  843. int    QFlag;                   /* double quoted string flag        */
  844. int    Q1Flag;                  /* single quoted string flag        */
  845. int    CsFlag;                  /* comment start flag               */
  846. int    CeFlag;                  /* comment end flag                 */
  847. int    CCnt;                    /* comment nesting level            */
  848. int    TFlag;                   /* transparency flag                */
  849.  
  850. /* EchoFlag tells whether or not the character is to echoed now     */
  851. /* or later.                                                        */
  852.  
  853.   QFlag  = FALSE;
  854.   Q1Flag = FALSE;
  855.   CsFlag = FALSE;
  856.   CeFlag = FALSE;
  857.   TFlag  = FALSE;
  858.   CCnt   = 0;
  859.  
  860.   rch:
  861.  
  862. /*                                                                  */
  863. /*  Fetch character from file                                       */
  864. /*                                                                  */
  865.  
  866.   C = FileChar(InFile,EofFlag);
  867.  
  868.   if (*EofFlag)
  869.     return(C);                  /* EOF encountered                  */
  870.  
  871.   if (EchoFlag)
  872.     return(C);
  873.  
  874.   Echo(C);
  875.  
  876.   if (TFlag)
  877.     {
  878.     TFlag = !TFlag;
  879.     goto rch;
  880.     }
  881.  
  882.   if (C == '\\')
  883.     {
  884.     TFlag = TRUE;
  885.     goto rch;
  886.     }
  887.  
  888. /*                                                                  */
  889. /*  If the character is not part of a quoted string check for and   */
  890. /*  process commented strings. Nested comments are handled          */
  891. /*  correctly but unbalanced comments are not. The assumption is    */
  892. /*  made that the syntax of the program being xref'd is correct.    */
  893. /*                                                                  */
  894.  
  895.   if (!QFlag && !Q1Flag)
  896.     {
  897.     if (C == '*' && CCnt && !CsFlag)
  898.       {
  899.       CeFlag = TRUE;
  900.       goto rch;
  901.       }
  902.  
  903.     if (C == '/' && CeFlag)
  904.       {
  905.       CCnt  -= 1;
  906.       CeFlag = FALSE;
  907.       goto rch;
  908.       }
  909.  
  910.     CeFlag = FALSE;
  911.  
  912.     if (C == '/')
  913.       {
  914.       CsFlag = TRUE;
  915.       goto rch;
  916.       }
  917.  
  918.     if (C == '*' && CsFlag)
  919.       {
  920.       CCnt  += 1;
  921.       CsFlag = FALSE;
  922.       goto rch;
  923.       }
  924.  
  925.     CsFlag = FALSE;
  926.  
  927.     if (CCnt)
  928.       goto rch;
  929.     }
  930.  
  931. /*                                                                  */
  932. /*  Check for and process quoted strings                            */
  933. /*                                                                  */
  934.  
  935.   if ( C == '"' && !Q1Flag)
  936.     {
  937.     QFlag = !QFlag;             /* toggle quote flag                */
  938.     goto rch;
  939.     }
  940.  
  941.   if (QFlag)
  942.     goto rch;
  943.  
  944.   if (C == '\'')
  945.     {
  946.     Q1Flag = !Q1Flag;           /* toggle quote flag                */
  947.     goto rch;
  948.     }
  949.  
  950.   if (Q1Flag)
  951.     goto rch;
  952.  
  953. /*                                                                  */
  954. /*  Valid character ... return to caller                            */
  955. /*                                                                  */
  956.  
  957.   return(C);
  958.   }
  959.  
  960. /********************************************************************/
  961.  
  962. int CheckToken(char *Token)
  963.   {
  964. char  UToken[MAX_LEN];
  965. int   I;
  966.  
  967.   if (RFlag)
  968.     return(TRUE);
  969.  
  970.   I = 0;
  971.  
  972.   do
  973.     {
  974.     UToken[I] = toupper(Token[I]);
  975.     }  while (Token[I++] != NULL);
  976.  
  977.   switch(UToken[0])
  978.     {
  979.   case 'A':
  980.     if (strcmp(UToken,"ASM")  == 0)
  981.       return(FALSE);
  982.  
  983.     if (strcmp(UToken,"AUTO") == 0)
  984.       return(FALSE);
  985.  
  986.     break;
  987.  
  988.   case 'B':
  989.     if (strcmp(UToken,"BREAK") == 0)
  990.       return(FALSE);
  991.  
  992.     break;
  993.  
  994.   case 'C':
  995.     if (strcmp(UToken,"CHAR") == 0)
  996.       return (FALSE);
  997.  
  998.     if (strcmp(UToken,"CDECL") == 0)
  999.       return (FALSE);
  1000.  
  1001.     if (strcmp(UToken,"CONST") == 0)
  1002.       return (FALSE);
  1003.  
  1004.     if (strcmp(UToken,"CONTINUE") == 0)
  1005.       return (FALSE);
  1006.  
  1007.     if (strcmp(UToken,"CASE") == 0)
  1008.       return (FALSE);
  1009.  
  1010.     break;
  1011.  
  1012.   case 'D':
  1013.     if (strcmp(UToken,"DOUBLE") == 0)
  1014.       return(FALSE);
  1015.  
  1016.     if (strcmp(UToken,"DO") == 0)
  1017.       return(FALSE);
  1018.  
  1019.     if (strcmp(UToken,"DEFAULT") == 0)
  1020.       return(FALSE);
  1021.     break;
  1022.  
  1023.   case 'E':
  1024.     if (strcmp(UToken,"EXTERN") == 0)
  1025.       return(FALSE);
  1026.  
  1027.     if (strcmp(UToken,"ELSE") == 0)
  1028.       return(FALSE);
  1029.  
  1030.     if (strcmp(UToken,"ENUM") == 0)
  1031.       return(FALSE);
  1032.  
  1033.     break;
  1034.  
  1035.   case 'F':
  1036.     if (strcmp(UToken,"FLOAT") == 0)
  1037.       return(FALSE);
  1038.  
  1039.     if (strcmp(UToken,"FOR") == 0)
  1040.       return(FALSE);
  1041.  
  1042.     if (strcmp(UToken,"FAR") == 0)
  1043.       return(FALSE);
  1044.  
  1045.     break;
  1046.  
  1047.   case 'G':
  1048.     if (strcmp(UToken,"GOTO") == 0)
  1049.       return(FALSE);
  1050.  
  1051.     break;
  1052.  
  1053.   case 'I':
  1054.     if (strcmp(UToken,"INT") == 0)
  1055.       return(FALSE);
  1056.  
  1057.     if (strcmp(UToken,"IF") == 0)
  1058.       return(FALSE);
  1059.  
  1060.     if (strcmp(UToken,"INTERRUPT") == 0)
  1061.       return(FALSE);
  1062.  
  1063.     break;
  1064.  
  1065.   case 'L':
  1066.     if (strcmp(UToken,"LONG") == 0)
  1067.       return(FALSE);
  1068.  
  1069.     break;
  1070.  
  1071.   case 'N':
  1072.     if (strcmp(UToken,"NEAR") == 0)
  1073.       return(FALSE);
  1074.  
  1075.     break;
  1076.  
  1077.   case 'P':
  1078.     if (strcmp(UToken,"PASCAL") == 0)
  1079.       return(FALSE);
  1080.  
  1081.     break;
  1082.  
  1083.  
  1084.   case 'R':
  1085.     if (strcmp(UToken,"RETURN") == 0)
  1086.       return(FALSE);
  1087.  
  1088.     if (strcmp(UToken,"REGISTER") == 0)
  1089.       return(FALSE);
  1090.  
  1091.     break;
  1092.  
  1093.   case 'S':
  1094.     if (strcmp(UToken,"STRUCT") == 0)
  1095.       return(FALSE);
  1096.  
  1097.     if (strcmp(UToken,"SHORT") == 0)
  1098.       return(FALSE);
  1099.  
  1100.     if (strcmp(UToken,"STATIC") == 0)
  1101.       return(FALSE);
  1102.  
  1103.     if (strcmp(UToken,"SIZEOF") == 0)
  1104.       return(FALSE);
  1105.  
  1106.     if (strcmp(UToken,"SWITCH") == 0)
  1107.       return(FALSE);
  1108.  
  1109.     if (strcmp(UToken,"SIGNED") == 0)
  1110.       return(FALSE);
  1111.  
  1112.     break;
  1113.  
  1114.   case 'T':
  1115.     if (strcmp(UToken,"TYPEDEF") == 0)
  1116.       return(FALSE);
  1117.  
  1118.     break;
  1119.  
  1120.   case 'U':
  1121.     if (strcmp(UToken,"UNION") == 0)
  1122.       return(FALSE);
  1123.  
  1124.     if (strcmp(UToken,"UNSIGNED") == 0)
  1125.       return(FALSE);
  1126.  
  1127.     break;
  1128.  
  1129.   case 'V':
  1130.     if (strcmp(UToken,"VOID") == 0)
  1131.       return(FALSE);
  1132.  
  1133.     if (strcmp(UToken,"VOLATILE") == 0)
  1134.       return(FALSE);
  1135.  
  1136.     break;
  1137.  
  1138.   case 'W':
  1139.     if (strcmp(UToken,"WHILE") == 0)
  1140.       return(FALSE);
  1141.  
  1142.     break;
  1143.     }
  1144.  
  1145.   return(TRUE);
  1146.   }
  1147.  
  1148. /********************************************************************/
  1149. /*                                                                  */
  1150. /*  Install parsed token and line reference in linked structure     */
  1151. /*                                                                  */
  1152. /********************************************************************/
  1153.  
  1154. void PutToken(char *Token,int Ref)
  1155.   {
  1156. unsigned int    HashIndex;
  1157. unsigned char  *Ptr;
  1158. struct IdBlk   *IdPtr;
  1159. struct HashBlk *HashPtr;
  1160.  
  1161.   if (LFlag)
  1162.     return;
  1163.  
  1164. /* Hashing algorithm is far from optimal but is adequate for a      */
  1165. /* memory-bound index vector!                                       */
  1166.  
  1167.   HashIndex = 0;
  1168.  
  1169.   for (Ptr = Token;*Ptr != '\0';Ptr++)
  1170.     HashIndex = HashIndex*10 + *Ptr;
  1171.  
  1172.   HashIndex = abs(HashIndex) % MAX_WRD;
  1173.   HashPtr   = &IdVector[HashIndex];
  1174.  
  1175.   if ((IdPtr = HashPtr -> IdFirst) == NULL)
  1176.     {
  1177.     IdCnt++;
  1178.     IdPtr               = AllocId(Token);
  1179.     HashPtr -> IdFirst  = IdPtr;
  1180.     HashPtr -> IdCount++;
  1181.     ChainAlpha(IdPtr,Token);
  1182.     IdPtr -> TopLnk     = AllocRf(Ref);
  1183.     IdPtr -> LstLnk     = IdPtr -> TopLnk;
  1184.     }
  1185.   else
  1186.     {
  1187.     for (;IdPtr != NULL;IdPtr = IdPtr -> IdNext)
  1188.       {
  1189.       if (strcmp(IdPtr -> IdName,Token) == 0)
  1190.         {
  1191.         IdPtr -> LstLnk = AddRf(IdPtr -> LstLnk,Ref);
  1192.         break;
  1193.         }
  1194.       }
  1195.  
  1196.     if (IdPtr == NULL)
  1197.       {
  1198.       IdCnt++;
  1199.       IdPtr               = AllocId(Token);
  1200.       IdPtr   -> IdNext   = HashPtr -> IdFirst;
  1201.       HashPtr -> IdFirst  = IdPtr;
  1202.       HashPtr -> IdCount++;
  1203.       ChainAlpha(IdPtr,Token);
  1204.       IdPtr   -> TopLnk   = AllocRf(Ref);
  1205.       IdPtr   -> LstLnk   = IdPtr -> TopLnk;
  1206.       }
  1207.     }
  1208.   }
  1209.  
  1210. /********************************************************************/
  1211.  
  1212. void ChainAlpha(struct IdBlk *CaPtr,char *CaToken)
  1213.   {
  1214. char          C;
  1215. struct IdBlk *CurPtr;
  1216. struct IdBlk *LstPtr;
  1217.  
  1218.   C = CaToken[0];
  1219.  
  1220.   if (C == '_')
  1221.     C = 0;
  1222.   else if (isupper(C))
  1223.     C = 1 + ((C - 'A')*2);
  1224.   else
  1225.     C = 2 + ((C - 'a')*2);
  1226.  
  1227.   if (AlphaVector[C].AlphaTop == NULL)
  1228.     {
  1229.     AlphaVector[C].AlphaTop = CaPtr;
  1230.     AlphaVector[C].AlphaLst = CaPtr;
  1231.     CaPtr -> AlphaLnk       = NULL;
  1232.     return;
  1233.     }
  1234.  
  1235. /*  check to see if new IdBlk should be inserted between the        */
  1236. /*  AlphaVector header block and the first IdBlk in the current     */
  1237. /*  alpha chain                                                     */
  1238.  
  1239.   if (strcmp(AlphaVector[C].AlphaTop -> IdName,CaToken) > 0)
  1240.     {
  1241.     CaPtr -> AlphaLnk       = AlphaVector[C].AlphaTop;
  1242.     AlphaVector[C].AlphaTop = CaPtr;
  1243.     return;
  1244.     }
  1245.  
  1246.   if (strcmp(AlphaVector[C].AlphaLst -> IdName,CaToken) < 0)
  1247.     {
  1248.     AlphaVector[C].AlphaLst -> AlphaLnk = CaPtr;
  1249.     CaPtr -> AlphaLnk                   = NULL;
  1250.     AlphaVector[C].AlphaLst             = CaPtr;
  1251.     return;
  1252.     }
  1253.  
  1254.   CurPtr = AlphaVector[C].AlphaTop;
  1255.  
  1256.   while (strcmp(CurPtr -> IdName,CaToken) < 0)
  1257.     {
  1258.     LstPtr = CurPtr;
  1259.     CurPtr = LstPtr -> AlphaLnk;
  1260.     }
  1261.  
  1262.   LstPtr -> AlphaLnk = CaPtr;
  1263.   CaPtr  -> AlphaLnk = CurPtr;
  1264.   return;
  1265.   }
  1266.  
  1267. /********************************************************************/
  1268.  
  1269. struct IdBlk *AllocId(char *Token)
  1270.   {
  1271. struct IdBlk *Ptr;
  1272.  
  1273.   if ((Ptr = (struct IdBlk *)malloc(sizeof(IdBlk))) == NULL)
  1274.     {
  1275.     printf("\nERROR: Unable to allocate identifier block\n");
  1276.     exit(1);
  1277.     }
  1278.  
  1279.   if ((Ptr -> IdName = malloc(strlen(Token) + 1)) == NULL)
  1280.     {
  1281.     printf("\nERROR: Unable to allocate identifier name block\n");
  1282.     exit(1);
  1283.     }
  1284.  
  1285.   strcpy(Ptr -> IdName,Token);
  1286.  
  1287.   Ptr -> AlphaLnk = NULL;
  1288.   Ptr -> IdNext   = NULL;
  1289.   Ptr -> TopLnk   = NULL;
  1290.   Ptr -> LstLnk   = NULL;
  1291.  
  1292.   return (Ptr);
  1293.   }
  1294.  
  1295. /********************************************************************/
  1296.  
  1297. struct RfBlk *AllocRf(int Ref)
  1298.   {
  1299. int           I;
  1300. struct RfBlk *Ptr;
  1301.  
  1302.   if ((Ptr = (struct RfBlk *)malloc(sizeof(RfBlk))) == NULL)
  1303.     {
  1304.     printf("\nERROR: Unable to allocate reference block\n");
  1305.     exit(1);
  1306.     }
  1307.  
  1308.   Ptr -> RefItem[0] = Ref;
  1309.   Ptr -> RefCnt     = 1;
  1310.   Ptr -> Next       = NULL;
  1311.  
  1312.   for (I = 1;I < MAX_REF;I++)
  1313.     Ptr -> RefItem[I] = 0;
  1314.  
  1315.   return (Ptr);
  1316.   }
  1317.  
  1318. /********************************************************************/
  1319.  
  1320. struct RfBlk *AddRf(struct RfBlk *Ptr,int Ref)
  1321.   {
  1322. struct RfBlk *TempPtr;
  1323.  
  1324.   TempPtr = Ptr;
  1325.  
  1326.   if (Ptr -> RefCnt == MAX_REF)
  1327.     {
  1328.     TempPtr     = AllocRf(Ref);
  1329.     Ptr -> Next = TempPtr;
  1330.     }
  1331.   else
  1332.     Ptr -> RefItem[Ptr -> RefCnt++] = Ref;
  1333.  
  1334.   return (TempPtr);
  1335.   }
  1336.  
  1337. /********************************************************************/
  1338.  
  1339. void PrintTable(void)
  1340.   {
  1341. int             Count;
  1342. int             I;
  1343. int             Ref;
  1344. int             LineCount;
  1345. int             RefsPerLine;
  1346. char            SaveFirst;
  1347. struct IdBlk   *IdPtr;
  1348. struct RfBlk   *TbPtr;
  1349. struct HashBlk *HashPtr;
  1350.  
  1351.   SaveFirst   = NULL;
  1352.   PrtRef      = TRUE;
  1353.   RefsPerLine = (MaxCol - 35) / 5;
  1354.  
  1355.   PrintHeader();
  1356.  
  1357.   for (I = 0;I < MAX_ALPHA;I++)                        /* for       */
  1358.     {
  1359.     if ((IdPtr = AlphaVector[I].AlphaTop) != NULL)     /* if 1      */
  1360.       {
  1361.       do                                               /* do 1      */
  1362.         {
  1363.         if (SaveFirst != IdPtr -> IdName[0])           /* if 2      */
  1364.           {
  1365.           NL();
  1366.           SaveFirst = IdPtr -> IdName[0];
  1367.           }                                            /* if 2      */
  1368.  
  1369.         if (OFlag)                                     /* if 3      */
  1370.           {
  1371.           if (fprintf(FLstFile,"%-33.32s: ",IdPtr -> IdName) == ERROR)
  1372.             ListErr();
  1373.           }                                            /* if 3      */
  1374.         else
  1375.           printf("%-33.32s: ",IdPtr -> IdName);
  1376.  
  1377.         TbPtr     = IdPtr -> TopLnk;
  1378.         LineCount = 0;
  1379.         Count     = 0;
  1380.  
  1381.         do                                             /* do 2      */
  1382.           {
  1383.           if (Count == MAX_REF)                        /* if 4      */
  1384.             {
  1385.             Count = 0;
  1386.             TbPtr = TbPtr -> Next;
  1387.             }                                          /* if 4      */
  1388.  
  1389.           if (TbPtr != NULL)                           /* if 5      */
  1390.             {
  1391.             if ((Ref = TbPtr -> RefItem[Count++]) != 0) /* if 6     */
  1392.               {
  1393.               if (OFlag)
  1394.                 {
  1395.                 if (fprintf(FLstFile,"%4d ",Ref) == ERROR)
  1396.                   ListErr();
  1397.                 }
  1398.               else
  1399.                 printf("%4d ",Ref);
  1400.  
  1401.               if (++LineCount == RefsPerLine)
  1402.                 {
  1403.                 NL();
  1404.  
  1405.                 if (OFlag)
  1406.                   {
  1407.                   if (fprintf(FLstFile,
  1408.                       "                                   ") == ERROR)
  1409.                     ListErr();
  1410.                   }
  1411.                 else
  1412.                   printf("                                   ");
  1413.  
  1414.                 LineCount = 0;
  1415.                 }
  1416.               }                                        /* if 6      */
  1417.             }                                          /* if 5      */
  1418.           else
  1419.             Ref = 0;
  1420.           } while (Ref);                               /* do 2      */
  1421.  
  1422.         NL();
  1423.  
  1424.         } while ((IdPtr = IdPtr -> AlphaLnk) != NULL); /* do 1      */
  1425.       }                                                /* if 1      */
  1426.     }                                                  /* for       */
  1427.  
  1428.   NL();
  1429.  
  1430.   if (SFlag)
  1431.     {
  1432.     PrintHeader();
  1433.  
  1434.     Count = 0;
  1435.  
  1436.     for (I = 0;I < MAX_WRD;I++)
  1437.       {
  1438.       HashPtr = &IdVector[I];
  1439.  
  1440.       if (HashPtr -> IdCount != 0)
  1441.         {
  1442.         Count++;
  1443.         CheckPage();
  1444.  
  1445.         if (OFlag)
  1446.           {
  1447.           if (fprintf(FLstFile,"%5d %04X %5d %s\n",
  1448.                       Count,I,
  1449.                       HashPtr -> IdCount,
  1450.                       HashPtr -> IdFirst -> IdName) == ERROR)
  1451.             ListErr();
  1452.           }
  1453.         else
  1454.           printf("%5d %04X %5d %s\n",
  1455.                  Count,I,
  1456.                  HashPtr -> IdCount,
  1457.                  HashPtr -> IdFirst -> IdName);
  1458.         }
  1459.       }
  1460.     }
  1461.   }
  1462.  
  1463. /********************************************************************/
  1464.  
  1465. void PrintHeader(void)
  1466.   {
  1467. int FileLen;
  1468. int CenterLen;
  1469. int NameStart;
  1470. int LeftLen;
  1471. int RightLen;
  1472.  
  1473.   FileLen   = strlen(GblFile);
  1474.   CenterLen = MaxCol - 29 - FileLen;
  1475.  
  1476.   if (CenterLen < 0)
  1477.     {
  1478.     NameStart = FileLen + CenterLen;
  1479.     LeftLen   = 0;
  1480.     RightLen  = 0;
  1481.     }
  1482.   else
  1483.     {
  1484.     NameStart = 0;
  1485.     LeftLen   = CenterLen >> 1;
  1486.     RightLen  = CenterLen - LeftLen;
  1487.     }
  1488.  
  1489.   if (OFlag)
  1490.     {
  1491.     if (fprintf(FLstFile,
  1492.                 "%cXC: C XREF Utility %*c%s%*c Page %4d\n\n",
  1493.                 FF,LeftLen,' ',&GblFile[NameStart],
  1494.                 RightLen,' ',++PageNo) == ERROR)
  1495.       ListErr();
  1496.     }
  1497.   else
  1498.     printf("%cXC: C XREF Utility %*c%s%*c Page %4d\n\n",
  1499.            FF,LeftLen,' ',&GblFile[NameStart],
  1500.            RightLen,' ',++PageNo);
  1501.  
  1502.   PageLine = 2;
  1503.   }
  1504.  
  1505. /********************************************************************/
  1506.  
  1507. void NL(void)
  1508.   {
  1509.   if (OFlag)
  1510.     {
  1511.     if (fprintf(FLstFile,"\n") == ERROR)
  1512.       ListErr();
  1513.      }
  1514.   else
  1515.     printf("\n");
  1516.  
  1517.   CheckPage();
  1518.  
  1519.   }
  1520.